package jxjc

import (
	"bytes"
	"encoding/json" // 引入 JSON 编码和解码包
	"fmt"
	"golang.org/x/crypto/ssh"
	"log"
	"net"
	"net/http"
	"strings"
	"time"
)

type Credentials struct {
	Host     string `json:"ip"`       // 使用 json 标签来映射 JSON 字段
	Username string `json:"username"` // 使用 json 标签来映射 JSON 字段
	Password string `json:"password"` // 使用 json 标签来映射 JSON 字段
}

func SubmitHandler(w http.ResponseWriter, r *http.Request) {
	// 设置允许跨域的响应头
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

	if r.Method == http.MethodOptions { // 如果是预检请求
		w.WriteHeader(http.StatusOK) // 返回 200
		return
	}

	if r.Method == http.MethodPost { // 如果是 POST 请求
		var creds Credentials // 创建一个 Credentials 结构体实例

		// 解析 JSON 数据
		err := json.NewDecoder(r.Body).Decode(&creds)
		if err != nil {
			http.Error(w, "无法解析 JSON 数据: "+err.Error(), http.StatusBadRequest) // 返回 400
			return                                                             // 结束
		}

		err1 := DeleteFile("../frontEnd/public/linuxcheck.json")
		if err1 != nil {
			fmt.Println("删除文件时出错:", err1)
		}

		//获取当前时间并打印到控制台
		currentTime := time.Now().Format("2006-01-02 15:04:05")
		fmt.Println("当前时间:", currentTime)
		// SSH 配置
		host := creds.Host + ":22" // 使用接收到的 IP 地址
		println(host)
		username := creds.Username // 使用接收到的用户名
		println(username)
		password := creds.Password // 使用接收到的密码
		println(password)

		localip := getLocalIP()
		// 定义脚本内容
		script := `
#!/usr/bin/env bash
webpath='/'
webhook_url='http://` + localip + `:6088/upload'

rm -f linuxcheck.json
# 设置保存文件
ipaddress=$(ip address | grep -oP '(?<=inet )\d+\.\d+\.\d+\.\d+(?=\/2)' | head -n 1)
current_time=$(date +"%H_%M_%S")
timestamped_filename="linuxcheck_${current_time}.json"
fixed_filename="linuxcheck.json"
echo $timestamped_filename  # 输出文件名

print_head() {
  local key="$1"
   printf "\"%s\":[\n" "$key" | tee -a "$fixed_filename" "$timestamped_filename"
}

print_tail() {
sed -i '$s/,$//' $fixed_filename
sed -i '$s/,$//' $timestamped_filename
echo -e "]," | tee -a "$fixed_filename" "$timestamped_filename"
}
printf "{\"key\":[\n"
print_linux() {
  local key="$1"
  local value="$2"
  # 使用 printf 和 sed 来替换换行符
   printf "{\"key\": \"%s\", \"value\": \"%s\"},\n" "$key" "$(echo "$value" | sed ':a;N;$!ba;s/\n/\\n/g' | sed 's/"/\\"/g')" | tee -a "$fixed_filename" "$timestamped_filename"
}

print_msg() {
  local key="$1"
  local value="$2"
  # 使用 printf 和 sed 来替换换行符
  printf "{\"text\": \"%s\", \"YN\": \"%s\"},\n" "$(echo "$value" | sed ':a;N;$!ba;s/\n/\\n/g' | sed 's/"/\\"/g')" "$key" | tee -a "$fixed_filename" "$timestamped_filename"
}

uptime=$(uptime | sed 's/.*up \([^,]*\), .*/\1/')

#调用函数库
[ -f /etc/init.d/functions ] && source /etc/init.d/functions
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
source /etc/profile

#Require root to run this script.
[ $(id -u) -gt 0 ] && echo "请用root用户执行此脚本！" && exit 1


echo -e "{" | tee -a "$fixed_filename" "$timestamped_filename"


function getSystemStatus(){
    if [ -e /etc/sysconfig/i18n ];then
        default_LANG="$(grep "LANG=" /etc/sysconfig/i18n | grep -v "^#" | awk -F '"' '{print $2}')"
    else
        default_LANG=$LANG
    fi
    export LANG="en_US.UTF-8"
    Release=$(cat /etc/redhat-release 2>/dev/null)
    Kernel=$(uname -r)
    OS=$(uname -o)
    Hostname=$(uname -n)
    SELinux=$(/usr/sbin/sestatus | grep "SELinux status: " | awk '{print $3}')
    LastReboot=$(who -b | awk '{print $3,$4}')
    uptime=$(uptime | sed 's/.*up \([^,]*\), .*/\1/')
    print_linux "系统" "$OS"
    print_linux "发行版本" "$Release"
    print_linux "内核" "$Kernel"
    print_linux "主机名" "$Hostname"
    print_linux "SELinux" "$SELinux"
    print_linux "语言/编码" "$default_LANG"
    print_linux "扫描时间" "$(date +'%F %T')"
    print_linux "最后启动" "$LastReboot"
    print_linux "运行时间" "$uptime"
    export LANG="$default_LANG"
}

bk_safe(){
  print_head "one"
  getSystemStatus
  print_tail

  print_head "two"
  action "[1] 账号策略检查中..." /bin/true
  
  passmax=$(cat /etc/login.defs | grep PASS_MAX_DAYS | grep -v ^# | awk '{print $2}')
  passmin=$(cat /etc/login.defs | grep PASS_MIN_DAYS | grep -v ^# | awk '{print $2}')
  passlen=$(cat /etc/login.defs | grep PASS_MIN_LEN | grep -v ^# | awk '{print $2}')
  passage=$(cat /etc/login.defs | grep PASS_WARN_AGE | grep -v ^# | awk '{print $2}')

  if [ $passmax -le 90 -a $passmax -gt 0 ];then
    print_msg "Y" "口令生存周期为${passmax}天，符合要求"
  else
    print_msg "N" "口令生存周期为${passmax}天，不符合要求,建议设置不大于90天"
  fi

  if [ $passmin -ge 6 ];then
    print_msg "Y" "口令更改最小时间间隔为${passmin}天，符合要求"
  else
    print_msg "N" "口令更改最小时间间隔为${passmin}天，不符合要求，建议设置大于等于6天"
  fi

  if [ $passlen -ge 8 ];then
    print_msg "Y" "口令最小长度为${passlen},符合要求"
  else
    print_msg "N" "口令最小长度为${passlen},不符合要求，建议设置最小长度大于等于8"
  fi

  if [ $passage -ge 30 -a $passage -lt $passmax ];then
    print_msg "Y" "口令过期警告时间天数为${passage},符合要求"
  else
    print_msg "N" "口令过期警告时间天数为${passage},不符合要求，建议设置大于等于30并小于口令生存周期"
  fi
  print_tail
  print_head "three"

  action "[2] 登录超时检查中..." /bin/true

  checkTimeout=$(cat /etc/profile | grep TMOUT | awk -F[=] '{print $2}')
  if [ $? -eq 0 ];then
    TMOUT=$(cat /etc/profile | grep TMOUT | awk -F[=] '{print $2}')
    if [ $TMOUT -le 600 -a $TMOUT -ge 10 ];then
      print_msg "Y" "账号超时时间${TMOUT}秒,符合要求"
    else
      print_msg "N" "账号超时时间${TMOUT}秒,不符合要求，建议设置小于600秒"
    fi
  else
    print_msg "N" "账号超时不存在自动注销,不符合要求，建议设置小于600秒"
  fi
  print_tail
  print_head "four"

  action "[3] 特权用户检查中..." /bin/true
  UIDS=$(awk -F[:] 'NR!=1{print $3}' /etc/passwd)
  flag=0
  for i in $UIDS
  do
    if [ $i = 0 ];then
       flag=1
    fi
  done
  if [ $flag != 1 ];then
    print_msg "Y" "不存在root账号外的UID为0的异常用户"
  else
    print_msg "N" "存在非root但UID为0的异常用户，请立刻进行排查"
  fi
  print_tail
  print_head "five"
  action "[4] 空登录口令用户检查中..." /bin/true

  userlist=$(awk -F: 'length($2)==0 {print $1}' /etc/shadow)
  [ ! $userlist ] && print_msg "Y" "不存在空登录口令用户"
  for i in $userlist
  do
    print_msg "N" "$i登录密码为空，不符合要求，建议为该用户设置密码！"
  done
  print_tail

  print_head "six"
  action "[6] 用户缺省权限检查中..." /bin/true

  umask1=$(cat /etc/profile | grep umask | grep -v ^# | awk '{print $2}')
  umask2=$(cat /etc/csh.cshrc | grep umask | grep -v ^# | awk '{print $2}')
  umask3=$(cat /etc/bashrc | grep umask | grep -v ^# | awk 'NR!=1{print $2}')
  flags=0
  for i in $umask1
  do
    if [ $i != "027" ];then
      print_msg "N" "/etc/profile文件中所所设置的umask为${i},不符合要求，建议设置为027"
      flags=1
      break
    fi
  done
  if [ $flags == 0 ];then
    print_msg "Y" "/etc/profile文件中所设置的umask为${i},符合要求"
  fi

  flags=0
  for i in $umask2
  do
    if [ $i != "027" ];then
      print_msg "N" "/etc/csh.cshrc文件中所所设置的umask为${i},不符合要求，建议设置为027"
      flags=1
      break
    fi
  done
  if [ $flags == 0 ];then
    print_msg "Y" "/etc/csh.cshrc文件中所设置的umask为${i},符合要求"
  fi
  flags=0
  for i in $umask3
  do
    if [ $i != "027" ];then
      print_msg "N" "/etc/bashrc文件中所设置的umask为${i},不符合要求，建议设置为027"
      flags=1
      break
    fi
  done
  if [ $flags == 0 ];then
    print_msg "Y" "/etc/bashrc文件中所设置的umask为${i},符合要求"
  fi
  print_tail
  print_head "seven"
  action "[7] 系统关键目录权限检查中..." /bin/true

  file1=$(ls -l /etc/passwd | awk '{print $1}')
  file2=$(ls -l /etc/shadow | awk '{print $1}')
  file3=$(ls -l /etc/group | awk '{print $1}')
  file4=$(ls -l /etc/securetty | awk '{print $1}')
  file5=$(ls -l /etc/services | awk '{print $1}')

  #检测文件权限为400的文件
  if [ $file2 = "-r--------" ];then
    print_msg "Y" "/etc/shadow文件权限为400，符合要求"
  else
    print_msg "N" "/etc/shadow文件权限不为400，不符合要求，建议设置权限为400"
  fi
  #检测文件权限为600的文件
  if [ $file4 = "-rw-------" ];then
    print_msg "Y" "/etc/security文件权限为600，符合要求"
  else
    print_msg "N" "/etc/security文件权限不为600，不符合要求，建议设置权限为600"
  fi

  #检测文件权限为644的文件
  if [ $file1 = "-rw-r--r--" ];then
    print_msg "Y" "/etc/passwd文件权限为644，符合要求"
  else
    print_msg "N" "/etc/passwd文件权限不为644，不符合要求，建议设置权限为644"
  fi
  if [ $file5 = "-rw-r--r--" ];then
    print_msg "Y" "/etc/services文件权限为644，符合要求"
  else
    print_msg "N" "/etc/services文件权限不为644，不符合要求，建议设置权限为644"
  fi
  if [ $file3 = "-rw-r--r--" ];then
    print_msg "Y" "/etc/group文件权限为644，符合要求"
  else
    print_msg "N" "/etc/group文件权限不为644，不符合要求，建议设置权限为644"
  fi
  print_tail
  print_head "eight"
  action "[8] ssh配置检查中..." /bin/true

  remoteLogin=$(cat /etc/ssh/sshd_config | grep -v ^# |grep "PermitRootLogin no")
  if [ $? -eq 0 ];then
    print_msg "Y" "已经设置root不能远程登陆，符合要求"
  else
    print_msg "N" "已经设置root能远程登陆，不符合要求，建议/etc/ssh/sshd_config添加PermitRootLogin no参数"
  fi
  print_tail
  print_head "nine"
  action "[9] 系统ping服务检查中..." /bin/true

  pingd=$(cat /proc/sys/net/ipv4/icmp_echo_ignore_all)
  if [ "$pingd" = "1" ]; then
    print_msg "Y" "服务器已禁ping"
  else
    print_msg "N" "服务器未禁ping"
  fi
  print_tail
  print_head "ten"
  action "[10] 系统telnet服务检查中..." /bin/true

  telnetd=$(rpm -qa|grep telnet | wc -l)
  if [ $telnetd = "0" ]; then
    print_msg "Y" "系统未安装telnet服务 "
  else
	print_msg "N" "检测到安装了telnet服务，不符合要求，建议禁用telnet服务"
  fi
  print_tail

  print_head "eleven"
  action "[11] 远程连接的安全性配置检查中..." /bin/true

  fileNetrc=$(find / -xdev -mount -name .netrc -print 2> /dev/null)
  if [  -z "${fileNetrc}" ];then
    print_msg "Y" "不存在.netrc文件，符合要求"
  else
    print_msg "N" "存在.netrc文件，不符合要求"
  fi
  fileRhosts=$(find / -xdev -mount -name .rhosts -print 2> /dev/null)
  if [ -z "$fileRhosts" ];then
    print_msg "Y" "不存在.rhosts文件，符合要求"
  else
    print_msg "N" "存在.rhosts文件，不符合要求"
  fi
  print_tail

  print_head "twelve"
  action "[12] 异常隐含文件检查中..." /bin/true

  hideFile=$(find / -xdev -mount \( -name "..*" -o -name "...*" \) 2> /dev/null)
  if [  -z "${hideFile}" ];then
    print_msg "Y" "不存在隐藏文件，符合要求"
  else
    print_msg "N" "存在隐藏文件，建议仔细检查："
	  print_arr  "${hideFile}"
  fi
  print_tail
  print_head "thirteen"
  action "[13] syslog登录事件检查中..." /bin/true

  if [  -f "/etc/syslog.conf" ];then
    logFile=$(cat /etc/syslog.conf | grep -V ^# | grep authpriv.*)
    if [ ! -z "${logFile}" ];then
      print_msg "Y" "存在保存authpirv的日志文件"
    else
      print_msg "N" "不存在保存authpirv的日志文件"
    fi
  else
    print_msg "N" "不存在／etc/syslog.conf文件，建议对所有登录事件都记录"
  fi
  print_tail
  print_head "fourteen"
  action "[14] 日志审核功能检查中..." /bin/true

  auditdStatus=$(service auditd status 2> /dev/null)
  if [ $? = 0 ];then
    print_msg "Y" "系统日志审核功能已开启，符合要求"
  fi
  if [ $? = 3 ];then
    print_msg "N" "系统日志审核功能已关闭，不符合要求，建议service auditd start开启"
  fi
  print_tail

  print_head "fifteen"
  action "[15] 系统core dump状态检查中..." /bin/true

  limitsFile=$(awk '$3 == "core"' /etc/security/limits.conf)
  if [ $? -eq 0 ];then
    soft=$(awk '$3 == "core" {print $2}' /etc/security/limits.conf)
    for i in $soft
    do
      if [ "$i"x = "soft"x ];then
        print_msg "Y" "* soft core 0 已经设置"
      fi
      if [ "$i"x = "hard"x ];then
        print_msg "Y" "* hard core 0 已经设置"
      fi
    done
  else
    print_msg "N" "没有设置core，建议在/etc/security/limits.conf中添加* soft core 0和* hard core 0"
  fi
  print_tail

}
bk_safe
sed -i '$s/,$//' $fixed_filename
sed -i '$s/,$//' $timestamped_filename
echo -e "}" | tee -a "$fixed_filename" "$timestamped_filename"

upload_report() {

  # 上传到指定接口
  if [[ -n $webhook_url ]]; then
    curl -X POST -F "file=@$timestamped_filename" "$webhook_url"  # 上传带时间戳的文件
    curl -X POST -F "file=@$fixed_filename" "$webhook_url"  # 上传固定文件名的文件
  fi

}
upload_report
echo -e "\nTIMESTAMPED_FILENAME:$timestamped_filename"
`

		// 连接并执行脚本
		output, timestampedFilename, err := executeSSH(host, username, password, script)
		if err != nil {
			log.Printf("执行失败: %v", err)
			http.Error(w, fmt.Sprintf("执行失败: %v", err), http.StatusInternalServerError)
			return
		}

		// 打印输出结果到日志
		log.Printf("输出结果:\n%s\n", output) // 打印输出结果
		log.Printf("生成的文件名: %s\n", timestampedFilename)
		// 输出结果到响应
		fmt.Fprintf(w, "输出结果:\n%s\n生成的文件名: %s\n", output, timestampedFilename)

		//调用数据库插入函数
		err = Linux_insert(username, host, currentTime, timestampedFilename)
		if err != nil {
			log.Printf("数据库插入失败: %v", err)
		} else {
			http.Error(w, "无效的请求方法", http.StatusMethodNotAllowed)
		}
	}
}

func isVirtualInterface(iface net.Interface) bool {
	virtualAdapters := []string{"VMware Network Adapter VMnet1", "VMware Network Adapter VMnet8"}
	for _, name := range virtualAdapters {
		if iface.Name == name {
			return true
		}
	}
	return false
}

func getLocalIP() string {
	interfaces, err := net.Interfaces()
	if err != nil {
		return fmt.Sprintf("Error: %v", err)
	}

	for _, iface := range interfaces {
		if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 && !isVirtualInterface(iface) {
			addrs, err := iface.Addrs()
			if err != nil {
				return fmt.Sprintf("Error: %v", err)
			}

			for _, addr := range addrs {
				if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil {
					return ipNet.IP.String()
				}
			}
		}
	}
	return ""
}

func executeSSH(host, username, password, script string) (string, string, error) {
	config := &ssh.ClientConfig{
		User: username,
		Auth: []ssh.AuthMethod{
			ssh.Password(password),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	client, err := ssh.Dial("tcp", host, config)
	if err != nil {
		return "", "", err
	}
	defer client.Close()

	// 创建会话
	session, err := client.NewSession()
	if err != nil {
		return "", "", err
	}
	defer session.Close()

	var stdoutBuf bytes.Buffer
	session.Stdout = &stdoutBuf

	if err := session.Run(script); err != nil {
		return "", "", fmt.Errorf("failed to run script: %v", err)
	}

	// 解析 stdoutBuf 的内容
	output := stdoutBuf.String()
	lines := strings.Split(output, "\n")
	var timestampedFilename string
	for _, line := range lines {
		if strings.HasPrefix(line, "TIMESTAMPED_FILENAME:") {
			timestampedFilename = strings.TrimPrefix(line, "TIMESTAMPED_FILENAME:")
			break
		}
	}

	return output, timestampedFilename, nil
}
